package org.demo.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.demo.Entity;
import org.demo.converter.LocalDateTimeConverter;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiFunction;

/**
 * excel工具类
 *
 * @author yexi
 */
@Slf4j
public class ExcelUtils {

    // 注册自定义转换器，按实际业务需要添加
    static {
        List<Converter> converterList = new ArrayList<>();
        converterList.add(new LocalDateTimeConverter());
        registerReadConverter(converterList);
        registerWriteConverter(converterList);
    }

    public static void registerReadConverter(List<Converter> converterList) {
        Map<String, Converter> readConverter = DefaultConverterLoader.loadDefaultReadConverter();
        for (Converter converter : converterList) {
            readConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
        }
    }

    public static void registerWriteConverter(List<Converter> converterList) {
        Map<String, Converter> writeConverter = DefaultConverterLoader.loadDefaultWriteConverter();
        for (Converter converter : converterList) {
            writeConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
        }
    }

    /**
     * 根据提供的实体类的属性注解定义，导出excel
     *
     * @param outputStream 输出流
     * @param sheetName    sheet名称
     * @param clazz        实体类，用于获取表头以及属性注解
     * @param data         实际导出数据
     */
    public static void export(OutputStream outputStream, String sheetName, Class clazz, List data) {
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(outputStream, clazz).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
            excelWriter.write(data, writeSheet);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 根据提供的表头，导出excel
     *
     * @param outputStream 输出流
     * @param sheetName    sheet名称
     * @param head         表头
     * @param data         实际导出数据
     */
    public static void export(OutputStream outputStream, String sheetName, List<List<String>> head, List data) {
        EasyExcel.write(outputStream)
                .head(head)
                .sheet(sheetName)
                .doWrite(data);
    }

    /**
     * 查找需要合并的单元格区域的行索引
     *
     * @param list             数据源列表
     * @param sameRuleFunction 判断行连续满足此规则的元素是需要合并的
     * @return 必然是2的倍数的基于数据源列表的行索引列表，比如列表只有0和2两个元素，则0-2就是要合并的行。
     */
    public static <T> List<Integer> findMergedRegionIndex(List<T> list, BiFunction<T, T, Boolean> sameRuleFunction) {
        List<Integer> result = new ArrayList<>();
        Integer start = null;
        for (int currentIndex = 0; currentIndex < list.size(); currentIndex++) {
            // 初始化，跳过第一行
            if (start == null) {
                start = currentIndex;
            } else {
                T now = list.get(currentIndex);
                int previousIndex = currentIndex - 1;
                T previous = list.get(previousIndex);
                // 如果跟上一次不一样，则前面的部分存在需要合并的行数
                if (!sameRuleFunction.apply(now, previous)) {
                    // 如果跟上一次就是定位起始行，也就是只有单行有差异，不需要处理合并
                    if (previousIndex == start) {
                        start = currentIndex;
                    } else {
                        // 记录开始至结束的行索引
                        result.add(start);
                        result.add(currentIndex - 1);
                        start = currentIndex;
                    }
                }
                // 行内容一直相同且到达了列表尾部，则剩下的全部都需要合并
                else if (currentIndex == list.size() - 1) {
                    result.add(start);
                    result.add(currentIndex);
                }
            }
        }
        return result;
    }


    public static void main(String[] args) throws IOException {
        Entity entity = Entity.builder().areaCode("区域").bandWidth("bandWidth").ignore(4L).mileage(23.65).order1("序列1").order2("序列2")
                .order3("序列3").order4("序列4").seqNo(7).mode("mode").name("测试").createTime(new Date())
                .updateTime(LocalDateTime.now()).build();
        Entity entity2 = Entity.builder().order1("序列1").order2("序列2")
                .order3("序列3").order4("序列4").seqNo(10).mode("mode").createTime(new Date())
                .updateTime(LocalDateTime.now()).build();
        List<Entity> entities = Arrays.asList(entity, entity2);
        // 自定义列表标题
        List<List<String>> headList = new ArrayList<>();
        List<String> head = new ArrayList<>();
        head.add("标题1");
        head.add("标题2");
        headList.add(head);
        List<String> head2 = new ArrayList<>();
        head2.add("标题3");
        head2.add("标题4");
        headList.add(head2);
        try (FileOutputStream outputStream = new FileOutputStream("filename.xlsx")) {
            export(outputStream, "sheet1", headList, entities);
        }
    }


}
